/*!
    \file  link32fa016bx_gpio.c
    \brief GPIO driver

    \version 2024-2-27, V1.0.0, firmware for LINK32FA016BX
*/


#include "link32fa016bx_gpio.h"

/*!
    \brief      reset GPIO port
    \param[in]  gpio_periph: GPIOx(x = 0, 1, 2, 3)
    \param[out] none
    \retval     none
*/
void gpio_deinit(uint32_t gpio_periph)
{
    switch (gpio_periph) {
        case GPIO0:
            /* reset GPIO0 */
            rcu_periph_reset_enable(RCU_RST_GPIO0);
            rcu_periph_reset_disable(RCU_RST_GPIO0);
            break;
        case GPIO1:
            /* reset GPIO1 */
            rcu_periph_reset_enable(RCU_RST_GPIO1);
            rcu_periph_reset_disable(RCU_RST_GPIO1);
            break;
        case GPIO2:
            /* reset GPIO2 */
            rcu_periph_reset_enable(RCU_RST_GPIO2);
            rcu_periph_reset_disable(RCU_RST_GPIO2);
            break;
        case GPIO3:
            /* reset GPIO3 */
            rcu_periph_reset_enable(RCU_RST_GPIO3);
            rcu_periph_reset_disable(RCU_RST_GPIO3);
            break;
        default:
            break;
    }
}

/*!
    \brief      GPIO initialization
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[out] none
    \retval     none
*/
void gpio_init(uint32_t gpio_periph)
{
    switch (gpio_periph) {
        case GPIO0:
            /* clock GPIO0 */
            rcu_periph_clock_enable(RCU_CLKON_GPIO0);
            break;
        case GPIO1:
            /* clock GPIO1 */
            rcu_periph_clock_enable(RCU_CLKON_GPIO1);
            break;
        case GPIO2:
            /* clock GPIO2 */
            rcu_periph_clock_enable(RCU_CLKON_GPIO2);
            break;
        case GPIO3:
            /* clock GPIO3 */
            rcu_periph_clock_enable(RCU_CLKON_GPIO3);
            break;
        default:
            break;
    }
}

/*!
    \brief      set GPIO Output Enable
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                one or more parameters can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     none
*/

void gpio_out_enable(uint32_t gpio_periph, uint32_t pin)
{
    GPIO_OE_SET(gpio_periph) = pin;
}

/*!
    \brief      set GPIO Output Disbale
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                one or more parameters can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     none
*/
void gpio_out_disable(uint32_t gpio_periph, uint32_t pin)
{
    GPIO_OE_CLR(gpio_periph) = pin;
}


/*!
    \brief      set GPIO pin
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                one or more parameters can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     none
*/
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
{
    GPIO_DATA_OUT(gpio_periph) |= pin;
}

/*!
    \brief      reset GPIO pin
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                one or more parameters can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     none
*/
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin)
{
    GPIO_DATA_OUT(gpio_periph) &= ~pin;
}

/*!
    \brief      write data to the specified GPIO pin
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                one or more parameters can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[in]  bit_value: SET or RESET
                only one parameter can be selected which is shown as below:
      \arg        RESET: clear the port pin
      \arg        SET: set the port pin
    \param[out] none
    \retval     none
*/
void gpio_bit_write(uint32_t gpio_periph, uint32_t pin, uint32_t bit_value)
{
    if (0 != bit_value) {
        gpio_bit_set(gpio_periph, pin);
    } else {
        gpio_bit_reset(gpio_periph, pin);
    }
}


/*!
    \brief      write data to the specified GPIO port
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  data: specify the value to be written to the port output data register
    \param[out] none
    \retval     none
*/
void gpio_port_write(uint32_t gpio_periph, uint16_t data)
{
    GPIO_DATA_OUT(gpio_periph) = (uint32_t) data;
}

/*!
    \brief      get GPIO pin input status
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                only one parameter can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     input status of gpio pin: 0 or 1
*/
FlagStatus gpio_input_bit_get(uint32_t gpio_periph, uint32_t pin)
{
    if (0 != (GPIO_DATA_IN(gpio_periph) & pin)) {
        return SET;
    } else {
        return RESET;
    }
}

/*!
    \brief      get GPIO port input status
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[out] none
    \retval     input status of gpio all pins
*/
uint16_t gpio_input_port_get(uint32_t gpio_periph)
{
    return (uint16_t)(GPIO_DATA_IN(gpio_periph));
}

/*!
    \brief      get GPIO pin output status
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[in]  pin: GPIO pin
                only one parameter can be selected which are shown as below:
      \arg        GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
    \param[out] none
    \retval     output status of gpio pin: 1 or 0
*/
FlagStatus gpio_output_bit_get(uint32_t gpio_periph, uint32_t pin)
{
    if (0 != (GPIO_DATA_OUT(gpio_periph) & pin)) {
        return SET;
    } else {
        return RESET;
    }
}

/*!
    \brief      get GPIO port output status
    \param[in]  gpio_periph: GPIOx(x = 0,1,2,3)
    \param[out] none
    \retval     output status of gpio all pins
*/
uint16_t gpio_output_port_get(uint32_t gpio_periph)
{
    return ((uint16_t) GPIO_DATA_OUT(gpio_periph));
}

void gpio_pin_af_set(uint32_t gpio_periph, uint32_t pidx, uint32_t afmux)
{
    uint32_t pin_idx;
    uint32_t temp;
    pin_idx = pidx & 0x7;
    GPIO_AF_SET(gpio_periph) = BIT(pidx);
    if(pidx >= 8) {
	temp = GPIO_AFMUX_8_15(gpio_periph) & (~GPIO_AFMUX_MASK(pin_idx));
        GPIO_AFMUX_8_15(gpio_periph) = temp | GPIO_AFMUX_SET(pin_idx, afmux);
    } else {
	temp = GPIO_AFMUX_0_7(gpio_periph) & (~GPIO_AFMUX_MASK(pin_idx));
        GPIO_AFMUX_0_7(gpio_periph) = temp | GPIO_AFMUX_SET(pin_idx, afmux);
    }
    return;
}

void gpio_pin_af_reset(uint32_t gpio_periph, uint32_t pidx)
{
    GPIO_AF_CLR(gpio_periph) = BIT(pidx);
}
